package org.orange.spring.mvc.simulate.coolingme.springframework.context.support;


import org.orange.spring.mvc.simulate.coolingme.springframework.beans.config.MeBeanDefinition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

/**
 * 读取并解析配置文件，支撑的作用
 *
 * @author wangyue
 * @date 2020/11/10 15:45
 */
public class MeBeanDefinitionReader {

    /**
     * 保存application.properties 配置文件中的
     */
    private Properties contextConfig = new Properties();

    /**
     * 固定配置文件中的 key，相对于xml的规范
     */
    private final String SCAN_PACKAGE = "scanPackage";

    /**
     * 保存扫描的所有类名，统一执行实例化操作
     */
    private List<String> registryBeanClasses = new ArrayList<>();


    /**
     * 加载配置文件
     *
     * @param configLocations 配置文件路径
     */
    public MeBeanDefinitionReader(String[] configLocations) {
        // 加载配置文件
        doLoadConfig(configLocations[0].replace("classpath:", ""));
        // 2、扫描相关类
        doScanner(contextConfig.getProperty(SCAN_PACKAGE));
    }

    /**
     * 1、加载配置文件
     *
     * @param contextConfigLocation 配置文件路径
     */
    private void doLoadConfig(String contextConfigLocation) {
        // 从类路径中找到配置文件所在路径
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {
            // 读取配置文件放到Properties对象中，及将配置从文件保存至内存中
            contextConfig.load(is);
            System.out.println("配置文件加载成功");
        } catch (IOException e) {
            System.err.println("未找到配置文件");
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 2、扫描相关的类
     *
     * @param scanPackage 被扫描的包名即com.coolingme.demo
     */
    private void doScanner(String scanPackage) {
        // 将 com.coolingme.demo 转为 文件路径，即把 . 换为 /
        String packageName = "/" + scanPackage.replaceAll("\\.", "/");
        // 获取 文件路径对象
        URL url = this.getClass().getClassLoader().getResource(packageName);

        //classpath 下不仅有.class文件，还有.xml文件 .properties文件
        assert url != null;
        File classpath = new File(url.getFile());
        // 当成是一个ClassPath文件夹
        for (File file : Objects.requireNonNull(classpath.listFiles())) {
            if (file.isDirectory()) {
                // 递归扫描
                doScanner(scanPackage + "." + file.getName());
            } else {
                // 只添加Java类
                if (!file.getName().endsWith(".class")) {
                    continue;
                }
                //全类名 = 包名.类名
                String className = scanPackage + "." + file.getName().replace(".class", "");
                registryBeanClasses.add(className);
            }
        }
    }

    /**
     * 把配置文件扫描到的所有配置信息转换成MeBeanDefinition对象，便于IoC操作方便
     *
     * @return MeBeanDefinition对象列表
     */
    public List<MeBeanDefinition> loadBeanDefinition() {
        List<MeBeanDefinition> result = new ArrayList<MeBeanDefinition>();
        try {
            for (String className : registryBeanClasses) {
                Class<?> beanClass = Class.forName(className);
                // 接口不能实例化
                if (beanClass.isInterface()) {
                    continue;
                }

                // factoryBeanName有三种情况
                // 1.默认为bean首字母小写
                // 2.自定义
                // 3.接口注入
                result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName()));

                // 获取类的父接口
                Class<?>[] interfaces = beanClass.getInterfaces();
                for (Class<?> interfaceClass : interfaces) {
                    // 如果是多个实现类，只能覆盖
                    // 这里可以自定义名称
                    //
                    result.add(doCreateBeanDefinition(interfaceClass.getName(), beanClass.getName()));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 创建MeBeanDefinition
     *
     * @param factoryBeanName 工厂中bean的名字
     * @param beanClassName   bean对应的名字
     * @return MeBeanDefinition
     */
    private MeBeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) {
        MeBeanDefinition beanDefinition = new MeBeanDefinition();
        beanDefinition.setFactoryBeanName(factoryBeanName);
        beanDefinition.setBeanClassName(beanClassName);
        return beanDefinition;
    }

    /**
     * 将类名首字母小写
     *
     * @param simpleName 类名
     * @return 小写类名
     */
    private String toLowerFirstCase(String simpleName) {
        char[] chars = simpleName.toCharArray();
        // 且大写字母的ASCII码要小于小写字母的ASCII码32
        chars[0] += 32;
        return String.valueOf(chars);
    }


}
